package forecasting.validation;

import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.util.List;
import java.util.Scanner;

import forecasting.Model;
import forecasting.util.FileUtils;


/**
 * Class used to evaluate Model by running the model for the provided
 * testing file and computes the error using the out testing file.
 */
public class ModelEvaluator {

	private double[] mErrors;	
			
	private double errorTotal = 0;
	
	private Model mModel = null;
	
	public ModelEvaluator(final Model model) {
		mModel = model;
	}
		
	public double evaulate(final String intest, final String outtest) {
		
		final Scanner intestScanner = FileUtils.openFileScanner(intest);
		final Scanner outtestScanner = FileUtils.openFileScanner(outtest);
		
		if (!intestScanner.hasNextLine() || !outtestScanner.hasNextLine()) {
			System.out.println("Input files are empty for Model Evaluation!");
			System.exit(-1);
		}
				
		// Trash the headers
		intestScanner.nextLine();
		outtestScanner.nextLine();
		
		final List<String> testList = FileUtils.scannerToList(intestScanner);				
		final List<String> outTestList = FileUtils.scannerToList(outtestScanner);
		mErrors = new double[testList.size()];				
		
		for (int i = 0; i < testList.size(); i++) {		
			final double prediction = mModel.run(testList.get(i));
			final double correct = Double.parseDouble(outTestList.get(i));
			mErrors[i] = findError(prediction, correct);
			errorTotal += mErrors[i];							
		}
		return errorTotal / mErrors.length;
	}
	
	public void reportErrors() {
		if (mErrors == null || mErrors.length == 0) {
			System.out.print("Nothing has been evaluated");
			return;
		}
		
		final double average = errorTotal / (mErrors.length * 100);
				
		System.out.println(String.format("WMAPE: %s", Double.toString(average)));
		System.out.println(String.format("Error Total: %s", Double.toString(errorTotal)));		
	}
	
	public void writeErrorsToFile(final String filename) {
		if (mErrors == null || mErrors.length == 0) {
			System.out.print("Nothing has been evaluated");
			return;
		}		
		
		PrintWriter outErrors = null;		
		try {
			outErrors = new PrintWriter(filename);
						
			// Create the training files
			for (int i = 0; i < mErrors.length; i++) {
				outErrors.println(mErrors[i]);				
			}					
		}  catch (FileNotFoundException e) {
			System.out.println(e);
			e.printStackTrace();
			System.exit(-1);
		} finally {
			outErrors.close();			
		}
	}
			
	protected static double findError(final double prediction, final double actual) {
		double error;
		if (actual > prediction) {
			error = 0.75 * (actual - prediction);
		} else {
			error = 0.25 * (prediction - actual);
		}
		return error;
	}
}
